
#include "stdafx.h"
#include "tinyxml2.h"
#include <string>

#if defined( _MSC_VER )
	#include <crtdbg.h>
	#define WIN32_LEAN_AND_MEAN
	#include <windows.h>
	_CrtMemState startMemState;
	_CrtMemState endMemState;
#endif

using namespace std;
using namespace tinyxml2;


static const char* APP_PROFILE = "app-profile.xml";

static const char* ELEMENT_APPLICATION = "application";
static const char* ELEMENT_JRE = "jre";
static const char* ELEMENT_JRE_VERSION = "version";
static const char* ELEMENT_MAIN_CLASS = "mainClass"; 
static const char* ELEMENT_DEPENDENCIES = "dependencies"; 
static const char* ELEMENT_JAR_DEPENDENCY = "jar"; 
static const char* ELEMENT_JAR_DEPENDENCY_ID = "id"; 
static const char* ELEMENT_JAR_DEPENDENCY_VERSION = "version"; 

static const char* JRE_INSTALL_DIR = ".\\jre\\";
static const char* JRE_EXE_PATH = "\\bin\\javaw.exe";
static const char* JAR_INSTALL_DIR = ".\\app\\";
static const char* JAR_PATH_SEPARATOR = ";";
static const char* JAR_NAME_VERSION_SEPARATOR = "-";
static const char* JAR_EXTENSION = ".jar";
static const char* CLASPPATH_SWITCH = " -classpath .";


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	// read the application profile 

	XMLDocument doc;	
	doc.LoadFile(APP_PROFILE);
	if (doc.ErrorID() != 0)
	{
		MessageBox ( NULL, TEXT("Unable to find launch settings ('app-profile.xml' is missing or invalid)"), TEXT("Launch Failed"), MB_OK );
		return FALSE;
	}

	XMLElement* appElement = doc.FirstChildElement(ELEMENT_APPLICATION);
	if (appElement == NULL)
	{
		MessageBox ( NULL, TEXT("Invalid 'app-profile.xml', the root element must be 'application'"), TEXT("Launch Failed"), MB_OK );
		return FALSE;
	}


	// load the JRE details
	
	XMLElement* jreElement = appElement->FirstChildElement(ELEMENT_JRE);
	if (jreElement == NULL)
	{
		MessageBox ( NULL, TEXT("Invalid 'app-profile.xml', no 'jre' definition found"), TEXT("Launch Failed"), MB_OK );
		return FALSE;
	}

	XMLElement* jreVersionElement = jreElement->FirstChildElement(ELEMENT_JRE_VERSION);
	if (jreVersionElement == NULL) 
	{
		MessageBox ( NULL, TEXT("Invalid 'app-profile.xml', 'version' is missing from JRE information"), TEXT("Launch Failed"), MB_OK );
		return FALSE;
	}
	string jreVersion = jreVersionElement->GetText();


	// load the main class to launch
	
	XMLElement* mainClassElement = appElement->FirstChildElement(ELEMENT_MAIN_CLASS);
	if (mainClassElement == NULL)
	{
		MessageBox ( NULL, TEXT("Invalid 'app-profile.xml', no 'mainClass' definition found"), TEXT("Launch Failed"), MB_OK );
		return FALSE;
	}
	string mainClass = mainClassElement->GetText();


	// load the classpath 

	string classpath;

	for(XMLElement* dependenciesElement = appElement->FirstChildElement(ELEMENT_DEPENDENCIES); 
		dependenciesElement != NULL; 
		dependenciesElement = dependenciesElement->NextSiblingElement(ELEMENT_DEPENDENCIES))
	{
		for(XMLElement* jarElement = dependenciesElement->FirstChildElement(ELEMENT_JAR_DEPENDENCY); 
			jarElement != NULL; 
			jarElement = jarElement->NextSiblingElement(ELEMENT_JAR_DEPENDENCY))
		{
			string id = jarElement->Attribute(ELEMENT_JAR_DEPENDENCY_ID);
			string version = jarElement->Attribute(ELEMENT_JAR_DEPENDENCY_VERSION);
			classpath += string(JAR_PATH_SEPARATOR) + JAR_INSTALL_DIR + id + JAR_NAME_VERSION_SEPARATOR + version + JAR_EXTENSION;
		}
	}


	// start the Java process

	string jrePath = JRE_INSTALL_DIR + jreVersion + JRE_EXE_PATH;
	string launchParams = CLASPPATH_SWITCH + classpath + " " + mainClass;

	STARTUPINFO         siStartupInfo;
    PROCESS_INFORMATION piProcessInfo;
    memset(&siStartupInfo, 0, sizeof(siStartupInfo));
    memset(&piProcessInfo, 0, sizeof(piProcessInfo));
    siStartupInfo.cb = sizeof(siStartupInfo);

    if(CreateProcess(jrePath.data(),		// Application name
					 (LPSTR)launchParams.data(),  // Application arguments
                     0,
                     0,
                     FALSE,
                     CREATE_DEFAULT_ERROR_MODE,
                     0,
                     0,                              // Working directory
                     &siStartupInfo,
                     &piProcessInfo) == FALSE)
	{
		 // Could not start application -> call 'GetLastError()'
		MessageBox(NULL, TEXT("There was an error while launching the application"), TEXT("Launch Failed"), MB_OK);
		return FALSE;
	}

    
	return TRUE;
}